package com.qiangesoft.batchsave.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qiangesoft.batchsave.entity.MallOrder;
import com.qiangesoft.batchsave.mapper.MallOrderMapper;
import com.qiangesoft.batchsave.service.IMallOrderService;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * <p>
 * 订单信息表 服务实现类
 * </p>
 *
 * @author qiangesoft
 * @since 2024-05-07
 */
@Service
public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder> implements IMallOrderService {

    @Override
    public void saveBatchXml(List<MallOrder> orderList) {
        baseMapper.saveBatch(orderList);
    }

    @Override
    public void insertBatchSomeColumn(List<MallOrder> orderList) {
        baseMapper.insertBatchSomeColumn(orderList);
    }

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Override
    public void manualCommit(List<MallOrder> orderList) {
        // 关闭自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
        MallOrderMapper mallOrderMapper = sqlSession.getMapper(MallOrderMapper.class);
        for (MallOrder mallOrder : orderList) {
            mallOrderMapper.insert(mallOrder);
        }

        sqlSession.commit();
        sqlSession.clearCache();
        sqlSession.close();
    }

    @Override
    public void executeBatch(List<MallOrder> orderList) {
        String sql = "insert into mall_order (" +
                "customer_id," +
                "order_status," +
                "payment_method," +
                "total_amount," +
                "shipping_fee," +
                "coupon_discount," +
                "order_date," +
                "payment_time," +
                "shipping_address," +
                "receiver_name," +
                "receiver_phone) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";

        SqlSession sqlSession = null;
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            sqlSession = sqlSessionFactory.openSession();
            connection = sqlSession.getConnection();
            connection.setAutoCommit(false);
            statement = connection.prepareStatement(sql);

            for (MallOrder mallOrder : orderList) {
                // 主键自增不设置
//                statement.setLong(0, mallOrder.getOrderId());
                statement.setLong(1, mallOrder.getCustomerId());
                statement.setInt(2, mallOrder.getOrderStatus());
                statement.setInt(3, mallOrder.getPaymentMethod());
                statement.setBigDecimal(4, mallOrder.getTotalAmount());
                statement.setBigDecimal(5, mallOrder.getShippingFee());
                statement.setBigDecimal(6, mallOrder.getCouponDiscount());
                statement.setObject(7, mallOrder.getOrderDate());
                statement.setObject(8, mallOrder.getPaymentTime());
                statement.setString(9, mallOrder.getShippingAddress());
                statement.setString(10, mallOrder.getReceiverName());
                statement.setString(11, mallOrder.getReceiverPhone());
                statement.addBatch();
            }
            statement.executeBatch();
            connection.commit();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if (sqlSession != null) {
                sqlSession.close();
            }
        }
    }

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private PlatformTransactionManager transactionManager;

    @Override
    public void saveBatchAsync(List<MallOrder> orderList) {
        int count = orderList.size();
        // 每批次插入的数据量
        int pageSize = 1000;
        // 线程数
        int threadNum = count % pageSize == 0 ? (count / pageSize) : (count / pageSize + 1);
        CountDownLatch countDownLatch = new CountDownLatch(threadNum);

        for (int i = 0; i < threadNum; i++) {
            int startIndex = i * pageSize;
            int endIndex = Math.min(count, (i + 1) * pageSize);
            List<MallOrder> subList = orderList.subList(startIndex, endIndex);
            threadPoolTaskExecutor.execute(() -> {
                DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
                TransactionStatus status = transactionManager.getTransaction(transactionDefinition);
                try {
                    this.saveBatch(subList);
                    transactionManager.commit(status);
                } catch (Exception exception) {
                    transactionManager.rollback(status);
                    throw exception;
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
